﻿/*
 * Copyright (C) 
 * Copyright (C) 
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

/* ScriptData
SDName: Boss_Nightbane
SD%Complete: 95
SDComment: SDComment: Timers may incorrect
SDCategory: Karazhan
EndScriptData */

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "karazhan.h"
#include "Reference.h"
#include "Unit.h"
#include "ObjectMgr.h"
#include "Reference.h"
#include "Player.h"
#pragma execution_character_set("utf-8")

//phase 1
#define SPELL_BELLOWING_ROAR        39427
#define SPELL_CHARRED_EARTH         30129
#define SPELL_DISTRACTING_ASH       30130
#define SPELL_SMOLDERING_BREATH     30210
#define SPELL_TAIL_SWEEP            25653
//phase 2
#define SPELL_RAIN_OF_BONES         37098
#define SPELL_SMOKING_BLAST         37057
#define SPELL_FIREBALL_BARRAGE      30282
#define SPELL_SEARING_CINDERS       30127
#define SPELL_SUMMON_SKELETON       30170

#define EMOTE_SUMMON                "一个古老的生物在远处苏醒过来……"
#define YELL_AGGRO                  "真是蠢蛋!我会快点结束你的痛苦!"
#define YELL_FLY_PHASE              "悲惨的害虫。我将让你消失在空气中!"
#define YELL_LAND_PHASE_1           "够了!我要亲自挑战你!"
#define YELL_LAND_PHASE_2           "昆虫!给你们近距离嚐嚐我的厉害!"
#define EMOTE_BREATH                "夜之魇深深地吸了一口气."

float IntroWay[8][3] =
{
	{ -11053.37f, -1794.48f, 149.00f }, //开始进入
	{ -11141.07f, -1841.40f, 125.00f },  //2阶段位置
	{ -11187.28f, -1890.23f, 125.00f },
	{ -11189.20f, -1931.25f, 125.00f },
	{ -11153.76f, -1948.93f, 125.00f },
	{ -11128.73f, -1929.75f, 125.00f },
	{ -11140.00f, -1915.00f, 122.00f },
	{ -11163.00f, -1903.00f, 91.473f }   //陆地？
};

class boss_nightbane : public CreatureScript
{
public:
	boss_nightbane() : CreatureScript("boss_nightbane") { }

	CreatureAI* GetAI(Creature* creature) const override
	{
		return GetInstanceAI<boss_nightbaneAI>(creature);
	}

	struct boss_nightbaneAI : public ScriptedAI
	{
		boss_nightbaneAI(Creature* c) : ScriptedAI(c)
		{
			Initialize();
			instance = c->GetInstanceScript();
			Intro = true;
			isReseted = false;
		}

		void Initialize()
		{
			BellowingRoarTimer = 30000;
			CharredEarthTimer = 15000;
			DistractingAshTimer = 20000;
			SmolderingBreathTimer = 10000;
			TailSweepTimer = 12000;
			RainofBonesTimer = 10000;
			SmokingBlastTimer = 20000;
			FireballBarrageTimer = 13000;
			SearingCindersTimer = 14000;
			WaitTimer = 1000;

			Phase = 1;
			FlyCount = 0;
			MovePhase = 0;
		}

		InstanceScript* instance;

		uint32 Phase;

		bool RainBones;
		bool Skeletons;

		uint32 BellowingRoarTimer;
		uint32 CharredEarthTimer;
		uint32 DistractingAshTimer;
		uint32 SmolderingBreathTimer;
		uint32 TailSweepTimer;
		uint32 RainofBonesTimer;
		uint32 SmokingBlastTimer;
		uint32 FireballBarrageTimer;
		uint32 SearingCindersTimer;

		uint32 FlyCount;
		uint32 FlyTimer;

		bool Intro;
		bool Flying;
		bool Movement;
		bool isReseted;

		uint32 WaitTimer;
		uint32 MovePhase;

		void Reset()
		{
			if (instance)
			{
				bool isCorrectSpawned = true;

				/*if (instance->GetData(TYPE_NIGHTBANE) != DONE)
				{
					uint64 NightbaneGUID = 0;
					NightbaneGUID = instance->GetData64(DATA_NIGHTBANE);

					if (NightbaneGUID)
					if (Creature* Nightbane = ObjectAccessor::GetCreature((*me), NightbaneGUID))
						isCorrectSpawned = false;
				}
				else
					isCorrectSpawned = false;*/

				if (!isCorrectSpawned)
				{
					(*me).GetMotionMaster()->Clear(false);
					isReseted = true;
					//me->DealDamage(me, me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
					me->RemoveCorpse();
				}
				else
				{
					instance->SetData64(DATA_NIGHTBANE, me->GetGUID());
				}

				if (!Intro)
				{
					(*me).GetMotionMaster()->Clear(false);
					isReseted = true;
					instance->SetData(TYPE_NIGHTBANE, NOT_STARTED);		
					//me->DealDamage(me, me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
					me->RemoveCorpse();
					return;
				}
				else
				{
					Initialize();

					me->SetSpeed(MOVE_RUN, 2.0f);
					me->SetDisableGravity(Intro);
					me->SetWalk(false);
					me->setActive(true);
					me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);

					if (instance)
					{
						if (instance->GetData(TYPE_NIGHTBANE) == DONE)
							me->DisappearAndDie();
						else
							instance->SetData(TYPE_NIGHTBANE, NOT_STARTED);
					}

					HandleTerraceDoors(true);

					Flying = false;
					Movement = false;

					if (!Intro)
					{
						me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0);
						me->GetMotionMaster()->MoveTargetedHome();
					}
				}
			}
		}

		void HandleTerraceDoors(bool open)
		{
			if (instance)
			{
				instance->HandleGameObject(instance->GetData64(DATA_MASTERS_TERRACE_DOOR_1), open);
				instance->HandleGameObject(instance->GetData64(DATA_MASTERS_TERRACE_DOOR_2), open);
			}
		}

		void EnterCombat(Unit* /*who*/) override
		{
			instance->SetBossState(DATA_NIGHTBANE, IN_PROGRESS);

			Initialize();
			HandleTerraceDoors(false);
			me->MonsterYell(YELL_AGGRO, LANG_UNIVERSAL, NULL);
		}

		void AttackStart(Unit* who)
		{
			if (!Intro && !Flying)
			if (Phase == 1)
				ScriptedAI::AttackStart(who);
			else
				AttackStartNoMove(who);
		}

		void JustDied(Unit* /*killer*/)
		{
			if (!isReseted)
			if (instance)
				instance->SetData(TYPE_NIGHTBANE, DONE);

			HandleTerraceDoors(true);
		}

		void MoveInLineOfSight(Unit *who)
		{
			if (!Intro && !Flying)
			if (!me->GetVictim() && me->CanStartAttack(who))
			if (Phase == 1)
				ScriptedAI::AttackStart(who);
			else
				AttackStartNoMove(who);
		}

		void MovementInform(uint32 type, uint32 id)
		{
			if (type != POINT_MOTION_TYPE)
				return;

			if (Intro)
			{
				if (id >= 8)
				{
					Intro = false;
					me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
					me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0);
					Phase = 1;
					return;
				}

				WaitTimer = 1;
			}

			if (Flying)
			{
				if (id == 0)
				{
					DoResetThreat();
					DoStartNoMovement(me->GetVictim());
					me->MonsterTextEmote(EMOTE_BREATH, 0, true);
					Skeletons = false;
					Flying = false;
					Phase = 2;
					return;
				}

				if (id == 3)
				{
					MovePhase = 4;
					WaitTimer = 1;
					return;
				}

				if (id == 8)
				{
					DoResetThreat();
					Flying = false;
					Phase = 1;
					Movement = true;
					return;
				}

				WaitTimer = 1;
			}
		}

		void JustSummoned(Creature* summoned) override
		{
			summoned->AI()->AttackStart(me->GetVictim());
		}

		void TakeOff()
		{
			me->MonsterYell(YELL_FLY_PHASE, LANG_UNIVERSAL, NULL);

			me->InterruptSpell(CURRENT_GENERIC_SPELL);
			me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
			me->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT | MOVEMENTFLAG_DISABLE_GRAVITY);
			(*me).GetMotionMaster()->Clear(false);
			(*me).GetMotionMaster()->MovePoint(0, IntroWay[2][0], IntroWay[2][1], IntroWay[2][2]);

			Flying = true;

			FlyTimer = urand(45000, 60000); //timer wrong between 45 and 60 seconds
			++FlyCount;

			RainofBonesTimer = 5000; //timer wrong (maybe)
			RainBones = false;
		}

		void UpdateAI(uint32 diff) override
		{
			if (WaitTimer)
			if (WaitTimer <= diff)
			{
				if (Intro)
				{
					if (MovePhase >= 7)
					{
						me->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT | MOVEMENTFLAG_DISABLE_GRAVITY);
						me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
						me->GetMotionMaster()->MovePoint(8, IntroWay[7][0], IntroWay[7][1], IntroWay[7][2]);
					}
					else
					{
						me->GetMotionMaster()->MovePoint(MovePhase, IntroWay[MovePhase][0], IntroWay[MovePhase][1], IntroWay[MovePhase][2]);
						++MovePhase;
					}
				}

				if (Flying)
				{
					if (MovePhase >= 7)
					{
						me->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT | MOVEMENTFLAG_DISABLE_GRAVITY);
						me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
						me->GetMotionMaster()->MovePoint(8, IntroWay[7][0], IntroWay[7][1], IntroWay[7][2]);
					}
					else
					{
						me->GetMotionMaster()->MovePoint(MovePhase, IntroWay[MovePhase][0], IntroWay[MovePhase][1], IntroWay[MovePhase][2]);
						++MovePhase;
					}
				}

				WaitTimer = 0;
			}
			else WaitTimer -= diff;

			if (!UpdateVictim())
				return;

			if (Flying)
				return;

			//  Phase 1 "GROUND FIGHT"
			if (Phase == 1)
			{
				if (Movement)
				{
					DoStartMovement(me->GetVictim());
					Movement = false;
				}

				if (BellowingRoarTimer <= diff)
				{
					DoCast(me->GetVictim(), SPELL_BELLOWING_ROAR);
					BellowingRoarTimer = urand(30000, 40000);
				}
				else BellowingRoarTimer -= diff;

				if (SmolderingBreathTimer <= diff)
				{
					DoCast(me->GetVictim(), SPELL_SMOLDERING_BREATH);
					SmolderingBreathTimer = 20000;
				}
				else SmolderingBreathTimer -= diff;

				if (CharredEarthTimer <= diff)
				{
					if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
						DoCast(pTarget, SPELL_CHARRED_EARTH);
					CharredEarthTimer = 20000;
				}
				else CharredEarthTimer -= diff;

				if (TailSweepTimer <= diff)
				{
					if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
					if (!me->HasInArc(M_PI, pTarget))
						DoCast(pTarget, SPELL_TAIL_SWEEP);
					TailSweepTimer = 15000;
				}
				else TailSweepTimer -= diff;

				if (SearingCindersTimer <= diff)
				{
					if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
						DoCast(pTarget, SPELL_SEARING_CINDERS);
					SearingCindersTimer = 10000;
				}
				else SearingCindersTimer -= diff;

				uint32 Prozent;
				Prozent = (me->GetHealth() * 100) / me->GetMaxHealth();

				if (Prozent < 75 && FlyCount == 0) // first take off 75%
					TakeOff();

				if (Prozent < 50 && FlyCount == 1) // secound take off 50%
					TakeOff();

				if (Prozent < 25 && FlyCount == 2) // third take off 25%
					TakeOff();

				DoMeleeAttackIfReady();
			}

			//Phase 2 "FLYING FIGHT"
			if (Phase == 2)
			{
				if (!RainBones)
				{
					if (RainofBonesTimer <= diff && !RainBones) // only once at the beginning of phase 2
					{
						if (!Skeletons)
						{
							for (int i = 0; i < 5; i++)
								DoCast(me->GetVictim(), SPELL_SUMMON_SKELETON, true);
							Skeletons = true;
						}

						DoCast(me->GetVictim(), SPELL_RAIN_OF_BONES);
						RainBones = true;
						SmokingBlastTimer = 20000;
					}
					else RainofBonesTimer -= diff;

					if (DistractingAshTimer <= diff)
					{
						if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
							DoCast(pTarget, SPELL_DISTRACTING_ASH);
						DistractingAshTimer = 2000; //timer wrong
					}
					else DistractingAshTimer -= diff;
				}

				if (RainBones)
				{
					if (SmokingBlastTimer <= diff)
					{
						DoCast(me->GetVictim(), SPELL_SMOKING_BLAST);
						SmokingBlastTimer = 1500; //timer wrong
					}
					else SmokingBlastTimer -= diff;
				}

				if (FireballBarrageTimer <= diff)
				{
					Map *map = me->GetMap();
					if (!map->IsDungeon()) return;
					Map::PlayerList const &PlayerList = map->GetPlayers();
					for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
					{
						if (Player* i_pl = i->GetSource())
						if (i_pl->IsAlive() && !me->IsWithinDistInMap(i_pl, 80))
						{
							DoCast(i_pl, SPELL_FIREBALL_BARRAGE);
						}
					}
					FireballBarrageTimer = 20000;
				}
				else FireballBarrageTimer -= diff;

				if (FlyTimer <= diff) //landing
				{
					me->MonsterYell(YELL_LAND_PHASE_1, LANG_UNIVERSAL, NULL);
					me->MonsterYell(YELL_LAND_PHASE_2, LANG_UNIVERSAL, NULL);
					me->GetMotionMaster()->Clear(false);
					me->GetMotionMaster()->MovePoint(3, IntroWay[3][0], IntroWay[3][1], IntroWay[3][2]);

					Flying = true;
				}
				else FlyTimer -= diff;
			}
		}
	};
};

struct npc_restless_skeletonAI : public ScriptedAI
{
	npc_restless_skeletonAI(Creature* pCreature) : ScriptedAI(pCreature) {}

	void Reset()
	{
		me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_ARCANE, true);
		me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FIRE, true);
		me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_SHADOW, true);
		me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true);
		me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
	}

	void UpdateAI(uint32 diff) override
	{
		if (!UpdateVictim())
			return;

		DoMeleeAttackIfReady();
	}
};

CreatureAI* GetAI_npc_restless_skeleton(Creature* pCreature)
{
	return new npc_restless_skeletonAI(pCreature);
};

class go_blackened_urn : public GameObjectScript
{
public:
    go_blackened_urn() : GameObjectScript("go_blackened_urn") { }

    bool OnGossipHello(Player* pPlayer, GameObject *pGo)
    {
		if (InstanceScript* pInstance = pGo->GetInstanceScript())
		{
			if (pInstance->GetData(TYPE_NIGHTBANE) != DONE && !pGo->FindNearestCreature(17225, 40.0f))
				if (Creature *cr = ObjectAccessor::GetCreature(*pPlayer, pInstance->GetData64(DATA_NIGHTBANE)))
					cr->GetMotionMaster()->MovePoint(0, IntroWay[0][0], IntroWay[0][1], IntroWay[0][2]);
		}        
		return false;
    }
};

void AddSC_boss_nightbane()
{
    new boss_nightbane();
	new go_blackened_urn();
}
